﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;
using AzureToolkit.Engine;
using Microsoft.Practices.ServiceLocation;

namespace AzureToolkit.Engine
{
    internal sealed class JobRunnerProcess : IInitializer
    {

        private IAzureQueue<RunJobMessage> runJobQueue;

        public JobRunnerProcess(JobSchedulingSettings settings)
        {
            this.runJobQueue = new AzureQueue<RunJobMessage>(settings.Account, settings.QueueName, settings.VisibilityTimeout);
        }

        public void Initialize()
        {
            this.runJobQueue.Initialize();
        }

        public void Run()
        {
            Trace.WriteLine("Running Job Runner Process.");
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    this.Cycle();
                }
            }, TaskCreationOptions.LongRunning);
        }

        private void Cycle()
        {
            try
            {
                var message = this.runJobQueue.GetMessage();
                if (message != null)
                {
                    this.runJobQueue.DeleteMessage(message);

                    ProcessMessage(message);

                    Thread.Sleep(TimeSpan.FromSeconds((new Random()).Next(20, 40)));
                }
                else
                {
                    Thread.Sleep(TimeSpan.FromSeconds(30));
                }
            }
            catch (TimeoutException)
            {
            }
        }

        private void ProcessMessage(RunJobMessage jobCommand)
        {
            Task.Factory.StartNew(() =>
            {
                try
                {
                    string jobName = jobCommand.JobName;
                    var job = (IJob)ServiceLocator.Current.GetInstance(Type.GetType(jobCommand.JobName));
                    string instanceId = RoleEnvironment.IsAvailable ? RoleEnvironment.CurrentRoleInstance.Id : "non-role-environment";
                    job.Run();
                }
                catch (Exception ex)
                {
                    var id = Guid.NewGuid().ToString();
                    Trace.TraceError(String.Format("{0} {1}", id, ex.TraceInformation()));
                    throw;
                }
            }, TaskCreationOptions.LongRunning);
        }
    }
}
